// Copyright (c) 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/**
*@describe:
*@author wfl19/Kristas
*@date 2021/08/28
 */

package convert

import (
	"errors"
	"reflect"
	"strconv"
)

func SetValue(src string, target reflect.Type, targetValue reflect.Value) error {
	if src == "" {
		return nil
	}
	reflect.ValueOf(src)
	v, err := Convert(src, target)
	if err != nil {
		return err
	}
	targetValue.Set(reflect.ValueOf(v))
	return nil
}

func Convert(src string, target reflect.Type) (interface{}, error) {
	if target.Kind() == reflect.Ptr {
		return convertMapping[target.Elem().Kind()](src, true)
	}
	return convertMapping[target.Kind()](src, false)
}

type convertHandler func(src string, ptr bool) (interface{}, error)

var convertMapping = map[reflect.Kind]convertHandler{
	reflect.Int:     intHandler,
	reflect.Int8:    int8Handler,
	reflect.Int16:   int16Handler,
	reflect.Int32:   int32Handler,
	reflect.Int64:   int64Handler,
	reflect.Uint:    uIntHandler,
	reflect.Uint8:   uInt8Handler,
	reflect.Uint16:  uInt16Handler,
	reflect.Uint32:  uInt32Handler,
	reflect.Uint64:  uInt64Handler,
	reflect.Bool:    boolHandler,
	reflect.Float32: float32Handler,
	reflect.Float64: float64Handler,
	reflect.String:  stringHandler,
}

func boolHandler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseBool(src)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return v, nil
}

func intHandler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.Atoi(src)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return v, nil
}

func int8Handler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseInt(src, 10, 8)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return int8(v), nil
}

func int16Handler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseInt(src, 10, 16)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return int16(v), nil
}

func int32Handler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseInt(src, 10, 32)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return int32(v), nil
}

func int64Handler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseInt(src, 10, 64)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return int64(v), nil
}

func uIntHandler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseUint(src, 10, 64)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return uint(v), nil
}

func uInt8Handler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseUint(src, 10, 8)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return uint8(v), nil
}

func uInt16Handler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseUint(src, 10, 16)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return uint16(v), nil
}

func uInt32Handler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseUint(src, 10, 32)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return uint32(v), nil
}

func uInt64Handler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseUint(src, 10, 64)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return uint64(v), nil
}

func float32Handler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseFloat(src, 32)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return float32(v), nil
}

func float64Handler(src string, ptr bool) (interface{}, error) {
	v, err := strconv.ParseFloat(src, 64)
	if err != nil {
		return nil, err
	}
	if ptr {
		return &v, nil
	}
	return v, nil
}

func stringHandler(src string, ptr bool) (interface{}, error) {
	if ptr {
		return &src, nil
	}
	return src, nil
}

func errNotSupport(k reflect.Kind) error {
	return errors.New("type " + k.String() + "not support")
}
